import json
import re

from django import http
from django.contrib.auth import login, logout
from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.paginator import Paginator
from django.shortcuts import render, redirect, reverse
from django.db.models import Count

from django.views import View
from django_redis import get_redis_connection

from apps.book.models import Book, Book_Commit, Book_Info

from apps.user.models import User, User_book


class Login(View):
    def get(self, request):
        return render(request, "user/login.html", context={"errmsg": ""})

    def post(self, request):
        data = json.loads(request.body.decode('utf-8'))

        username = data.get("email")
        pwd = data.get("password")
        vercode = data.get("vercode")
        image_token = data.get("image_token")

        if not all([image_token, vercode, pwd, username]):
            return http.JsonResponse({'code': "7410", 'errmsg': '数据异常，登录失败'})

        redis_conn = get_redis_connection('code')
        t_f = redis_conn.get("img_%s" % image_token + "/")
        if not t_f:
            return http.JsonResponse({'code': "7410", 'errmsg': '验证码错误'})
        if t_f.decode().lower() != vercode.lower():
            return http.JsonResponse({'code': "200", 'errmsg': '验证码错误'})

        if username.isdigit() and len(username) != 11:
            return http.JsonResponse({'code': "201", 'errmsg': '手机号错误'})

        if re.search(r'^\d{11}$', username):
            # 手机号登录
            user = User.objects.filter(mobile=username)
            if not user:
                return http.JsonResponse({'code': "200", 'errmsg': '手机号不存在'})
        else:
            # 邮箱登录
            user = User.objects.filter(email=username)
            if not user:
                return http.JsonResponse({'code': "200", 'errmsg': '邮箱不存在'})
        if not user[0].check_password(pwd):
            return http.JsonResponse({'code': "200", 'errmsg': '密码错误'})
        login(request, user[0])
        return http.JsonResponse({'code': "0", 'errmsg': '登录成功'})


class Register(View):
    def get(self, request):

        return render(request, "user/reg.html")

    def post(self, request):
        data = json.loads(request.body.decode('utf-8'))
        phone_num = data.get("email")
        sms_code = data.get("sms_code")
        pwd1 = data.get("password")
        pwd2 = data.get("password2")
        username = data.get("username")
        if not 5 <= len(username) <= 20:
            return http.JsonResponse({'code': "7419", 'errmsg': '用户名只能是5-20位字符'})
        if not all([phone_num, sms_code, pwd1, pwd2, username]):
            return http.JsonResponse({'code': "7410", 'errmsg': '缺少数据'})

        if pwd2 != pwd1:
            return http.JsonResponse({'code': "7850", 'errmsg': '两次密码不一样'})
        if not 6 <= len(pwd2) <= 16:
            return http.JsonResponse({'code': "7545", 'errmsg': '密码长度错误'})

        if not sms_code.isdigit():
            return http.JsonResponse({'code': "7845", 'errmsg': '请输入正确的短信验证码'})
        redis_conn = get_redis_connection('code')
        redis_phone_num = redis_conn.get("phone_code_%s" % phone_num)
        if not redis_phone_num:
            return http.JsonResponse({'code': "7847", 'errmsg': '短信验证码错误'})
        if int(redis_phone_num) != int(sms_code):
            return http.JsonResponse({'code': "7846", 'errmsg': '短信验证码错误'})
        try:
            User.objects.get(username=username)
            return http.JsonResponse({'code': "7845", 'errmsg': '该用户名已存在'})
        except:
            try:
                User.objects.get(mobile=phone_num)
                return http.JsonResponse({'code': "7845", 'errmsg': "该手机号已被注册"})
            except:
                pass
        try:
            print(pwd2, phone_num, username)
            user = User.objects.create_user(username=username, password=pwd2, mobile=phone_num)
        except:
            return http.JsonResponse({'code': "7845", 'errmsg': '注册失败'})
        redis_conn.delete(redis_phone_num)
        login(request, user)
        return http.JsonResponse({'code': "0", 'errmsg': '/'})


class User_info(LoginRequiredMixin, View):
    def get(self, request):
        content = {
            "username": request.user.username,
            "gender": request.user.gender,
            "desc": request.user.description
        }
        return render(request, "user/user_info.html", context=content)

    def post(self, request):
        data = json.loads(request.body.decode('utf-8'))
        # 获取数据
        name = data.get("name")
        gender = data.get("sex")
        desc = data.get("desc")
        # 判断是否有必要的数据
        if not all([name, gender]):
            return http.JsonResponse({'code': "45855", 'errmsg': '缺少数据'})
        # 判断数据是否合理
        if gender not in ["0", "1"]:
            return http.JsonResponse({'code': "45855", 'errmsg': '数据错误'})
        # 判断用户名是否在2-10
        if not 2 <= len(name) <= 10:
            return http.JsonResponse({'code': "45855", 'errmsg': '用户名长度错误'})

        user = request.user
        user.gender = gender
        # 判断用户名是否发生改变
        if user.username != name:
            # 如果要修改的用户名已经有人使用则不允许修改
            if User.objects.filter(username=name):
                return http.JsonResponse({'code': "4585", 'errmsg': '该用户名已被占用'})
            user.username = name
        #     判断是否有用户自我描述是否
        if desc and len(desc) <= 140:
            user.description = desc
        user.save()
        return http.JsonResponse({'code': "0", 'errmsg': '修改成功'})


class User_head(LoginRequiredMixin, View):
    def get(self, request):
        content = {
            "user": request.user
        }
        return render(request, "user/user_head_set.html", context=content)


class Upload_image(LoginRequiredMixin, View):
    def post(self, request):
        content = {
            "user": request.user
        }
        img_id = request.POST.get("id", "200")
        if not img_id.isdigit():
            return render(request, "user/user_head_set.html", context=content)
        if not 200 <= int(img_id) <= 292:
            return render(request, "user/user_head_set.html", context=content)

        url = "//q2apgq6sj.bkt.clouddn.com/%s.png" % img_id
        request.user.img_url = url
        request.user.save()
        return render(request, "user/user_head_set.html", context=content)


class Commit(LoginRequiredMixin, View):
    def get(self, request):
        num = request.GET.get("num", "1")
        # 分组， 查询用户评论的小说，以小说外键作为分组规则， 查询出来的是个字典
        books = Book_Commit.objects.values("chapter").annotate(Count=Count("chapter")).filter(author=request.user,
                                                                                              is_deleted=False)
        # 获取小说章节的id
        lists = []
        for i in books:
            lists.append(i["chapter"])
        # 获取小说信息
        book = Book.objects.filter(book_info__in=lists)
        # 将小说去重
        a = set()
        for i in book:
            a.add(i)
        # 去重后的数据转换为列表，进行分页
        book = list(a)
        pg = Paginator(book, 6)
        # 判断是否有分页num，并且num是否合格
        if num and num.isdigit():
            page = pg.page(num)
        else:
            page = pg.page(1)
        # 添加一个总变量
        page.num_pages = pg.num_pages
        page.counts = len(book)
        content = {
            "book": book,
            "user": request.user,
            "page": page,
        }
        return render(request, "user/user_commit.html", context=content)

    def post(self, request):
        data = json.loads(request.body.decode('utf-8'))
        book_id = data.get("book_id")
        book_catalog_num = data.get("book_catalog_num")
        commit = data.get("commit")
        print(data)
        if not all([book_id, book_catalog_num, commit]):
            return http.JsonResponse({"code": "95247", "errmsg": "缺少数据，评论失败"})
        book = Book_Info.objects.filter(order_id=book_catalog_num, book_id=book_id)
        if len(commit) > 200:
            return http.JsonResponse({"code": "9547", "errmsg": "评论内容过长，评论失败"})
        if not book:
            return http.JsonResponse({"code": "95247", "errmsg": "数据错误，评论失败"})
        try:
            Book_Commit.objects.create(commit=commit, chapter=book[0], author=request.user)
            return http.JsonResponse({"code": "0", "errmsg": "评论成功"})
        except:
            return http.JsonResponse({"code": "9547", "errmsg": "数据错误，评论失败"})


class My_commit(LoginRequiredMixin, View):
    def get(self, request, uuid):
        # 获取当前小说
        book = Book.objects.filter(id=uuid)

        if not book:
            return render(request, "404.html")
        # 获取用户对该小说的评论
        book_commit = Book_Commit.objects.filter(author=request.user, chapter__book__id=uuid, is_deleted=False)
        content = {
            "book": book[0],
            "book_commit": book_commit,
            "user": request.user
        }
        return render(request, "user/my_commit.html", context=content)

    def delete(self, request, uuid):
        data = json.loads(request.body.decode('utf-8'))
        book_id = data.get("book_id")
        if not book_id:
            return http.JsonResponse({"code": "78545", "errmsg": "数据错误"})
        book = Book_Commit.objects.filter(id=book_id, author=request.user)
        if not book:
            return http.JsonResponse({"code": "78545", "errmsg": "数据错误"})
        book[0].is_deleted = True
        book[0].save()
        return http.JsonResponse({"code": "0", "errmsg": "删除成功"})


class My_book_list(LoginRequiredMixin, View):
    def get(self, request):
        # 获取页数
        num = request.GET.get("num", "1")
        # 获取用户书架数据
        book = User_book.objects.filter(user=request.user, is_del=False)
        lists = []
        for i in book:
            lists.append(i.book.group_id)
        # 如果用户书架中没有收藏书架则推荐最新的小说个用户
        if lists:
            tj_book = Book.objects.filter(group_id=max(lists))[:6]
        else:
            tj_book = Book.objects.filter(group_id=max(lists))[:6]
        # 分页，一页7个
        pg = Paginator(book, 7)
        # 判断用户传递过来的分页数据是否合理
        if num.isdigit() and int(num) <= pg.num_pages:
            book = pg.page(num)
        else:
            book = pg.page(1)
        #   获取总页数
        book.num_pages = pg.num_pages
        # 获取总个数
        book.nums = pg.count
        content = {
            "book": book,
            "page": book,
            "tj_book": tj_book,
            "user": request.user
        }
        return render(request, "user/my_book_list.html", context=content)

    def post(self, request):
        data = json.loads(request.body.decode('utf-8'))
        book_id = data.get("book_id")
        # 判断是否有book_id
        if not book_id:
            return http.JsonResponse({"code": "85201", "errmsg": "数据错误"})
        try:
            # 判断要添加的书的id是否在该图书中
            book = Book.objects.get(id=book_id)
        except:
            return http.JsonResponse({"code": "85201", "errmsg": "数据错误"})
        t_f = User_book.objects.filter(user=request.user, book=book)
        # 判断要添加书籍的书是否已经在书架中了
        if not t_f:
            # 如果没有则添加
            book_info = book.book_info_set.first()
            User_book.objects.create(user=request.user, book=book, book_info=book_info)
        else:
            # 如果要添加的小说是逻辑删除， 则将逻辑删除关闭
            t_f[0].is_del = False
            t_f[0].save()
        return http.JsonResponse({"code": "0", "errmsg": "添加成功"})

    def delete(self, request):
        data = json.loads(request.body.decode('utf-8'))
        book_id = data.get("book_id")
        # 判断是否有book_id
        if not book_id:
            return http.JsonResponse({"code": "85201", "errmsg": "数据错误"})
        # 判断用户是否收藏该小说
        try:
            book = User_book.objects.get(user=request.user, book_id=book_id)
        except:
            return http.JsonResponse({"code": "85205", "errmsg": "数据错误"})
        # 逻辑删除
        book.is_del = True
        book.save()
        return http.JsonResponse({"code": "0", "errmsg": "删除成功"})


class Logout(View):
    def get(self, request):
        logout(request)
        red = redirect(reverse("index:index"))
        return red


class Forget(View):
    def get(self, request):
        return render(request, "user/reset_pwd.html")

    def post(self, request):
        data = json.loads(request.body.decode('utf-8'))
        mobile = data.get("email")
        sms_code = data.get("sms_code")
        pwd1 = data.get("password")
        pwd2 = data.get("password2")

        if not all([mobile, sms_code, pwd1, pwd2]):
            return http.JsonResponse({'code': "7410", 'errmsg': '缺少数据'})

        if pwd2 != pwd1:
            return http.JsonResponse({'code': "7850", 'errmsg': '两次密码不一样'})
        if not 6 <= len(pwd2) <= 16:
            return http.JsonResponse({'code': "7545", 'errmsg': '密码长度错误'})

        if not sms_code.isdigit():
            return http.JsonResponse({'code': "7845", 'errmsg': '请输入正确的短信验证码'})
        redis_conn = get_redis_connection('code')
        redis_phone_num = redis_conn.get("phone_code_%s" % mobile)
        if not redis_phone_num:
            return http.JsonResponse({'code': "7847", 'errmsg': '短信验证码错误'})
        if int(redis_phone_num) != int(sms_code):
            return http.JsonResponse({'code': "7846", 'errmsg': '短信验证码错误'})
        user = User.objects.filter(mobile=mobile)
        if not user:
            return http.JsonResponse({'code': "7846", 'errmsg': '手机号不存在'})
        try:
            user[0].set_password(pwd2)
            user[0].save()
            redis_conn.delete(redis_phone_num)
            return http.JsonResponse({'code': "0", 'errmsg': '密码修改成功'})
        except:
            return http.JsonResponse({'code': "7846", 'errmsg': '密码修改失败'})


class Chang_pwd(LoginRequiredMixin, View):
    def get(self, request):
        content = {
            "username": request.user.username
        }
        return render(request, "user/chang_pwd.html", context=content)

    def post(self, request):
        data = json.loads(request.body.decode('utf-8'))

        old_pwd = data.get('old_pwd')
        new_pwd1 = data.get('new_pwd1')
        new_pwd2 = data.get('new_pwd2')
        if not all([old_pwd, new_pwd1, new_pwd2]):
            return http.JsonResponse({"code": "1252", "errmsg": "缺失数据"})
        if new_pwd2 != new_pwd1:
            return http.JsonResponse({"code": "1252", "errmsg": "两次密码不一致"})
        if not 6 <= len(new_pwd1) <= 16:
            return http.JsonResponse({"code": "1581", "errmsg": "密码长度错误"})
        t_f = request.user.check_password(old_pwd)
        if t_f:
            try:
                request.user.set_password(new_pwd1)
                request.user.save()
                return http.JsonResponse({"code": "0", "errmsg": "密码修改成功"})
            except:
                return http.JsonResponse({"code": "1581", "errmsg": "密码修改错误"})
        return http.JsonResponse({"code": "7410", "errmsg": "原密码错误"})

